---
title: Menu
description: Using the menu machine in your project.
package: "@zag-js/menu"
---

An accessible dropdown and context menu that is used to display a list of
actions or options that a user can choose.

<Resources pkg="@zag-js/menu" />

<Showcase id="Menu" />

**Features**

- Support for items, labels, groups of items
- Focus is fully managed using `aria-activedescendant` pattern
- Typeahead to allow focusing items by typing text
- Keyboard navigation support including arrow keys, home/end, page up/down

## Installation

To use the menu machine in your project, run the following command in your
command line:

<CodeSnippet id="menu/installation.mdx" />

## Anatomy

To set up the menu correctly, you'll need to understand its anatomy and how we
name its parts.

> Each part includes a `data-part` attribute to help identify them in the DOM.

<Anatomy id="menu" />

## Usage

First, import the menu package into your project

```jsx
import * as menu from "@zag-js/menu"
```

The menu package exports two key functions:

- `machine` — The state machine logic for the menu widget.
- `connect` — The function that translates the machine's state to JSX attributes
  and event handlers.

> You'll need to provide a unique `id` to the `useMachine` hook. This is used to
> ensure that every part has a unique identifier.

Next, import the required hooks and functions for your framework and use the
menu machine in your project 🔥

<CodeSnippet id="menu/usage.mdx" />

### Listening for item selection

When a menu item is clicked, the `onSelect` callback is invoked.

```jsx {3-6}
const service = useMachine(menu.machine, {
  onSelect(details) {
    // details => { value: string }
    console.log("selected value is ", details.value)
  },
})
```

### Listening for open state changes

When a menu is opened or closed, the `onOpenChange` callback is invoked.

```jsx {3-6}
const service = useMachine(menu.machine, {
  onOpenChange(details) {
    // details => { open: boolean }
    console.log("open state is ", details.open)
  },
})
```

### Grouping menu items

When the number of menu items gets much, it might be useful to group related
menu items. To achieve this:

- Wrap the menu items within an element.
- Spread the `api.getGroupProps(...)` JSX properties unto the element, providing
  an `id`.
- Render a label for the menu group, providing the `id` of the group element.

```jsx
//...
<div {...api.getContentProps()}>
  {/* ... */}
  <hr {...api.getSeparatorProps()} />
  <p {...api.getItemGroupLabelProps({ htmlFor: "account" })}>Accounts</p>
  <div {...api.getItemGroupProps({ id: "account" })}>
    <button {...api.getItemProps({ value: "account-1" })}>Account 1</button>
    <button {...api.getItemProps({ value: "account-2" })}>Account 2</button>
  </div>
</div>
//...
```

### Checkbox and Radio option items

To use checkbox or radio option items, you'll need to:

- Add a `value` property to the machine's context whose value is an object
  describing the state of the option items.
- Use the `api.getOptionItemProps(...)` function to get the props for the option
  item.

A common requirement for the option item that you pass the `name`, `value` and
`type` properties.

- `type` — The type of option item. Either `"checkbox"` or `"radio"`.
- `value` — The value of the option item.
- `checked` — The checked state of the option item.
- `onCheckedChange` — The callback to invoke when the checked state changes.

<CodeSnippet id="menu/option-items.mdx" />

## Styling guide

Earlier, we mentioned that each menu part has a `data-part` attribute added to
them to select and style them in the DOM.

### Open and closed state

When the menu is open or closed, the content and trigger parts will have the
`data-state` attribute.

```css
[data-part="content"][data-state="open|closed"] {
  /* styles for open or closed state */
}

[data-part="trigger"][data-state="open|closed"] {
  /* styles for open or closed state */
}
```

### Highlighted item state

When an item is highlighted, via keyboard navigation or pointer, it is given a
`data-highlighted` attribute.

```css
[data-part="item"][data-highlighted] {
  /* styles for highlighted state */
}

[data-part="item"][data-type="radio|checkbox"][data-highlighted] {
  /* styles for highlighted state */
}
```

### Disabled item state

When an item or an option item is disabled, it is given a `data-disabled`
attribute.

```css
[data-part="item"][data-disabled] {
  /* styles for disabled state */
}

[data-part="item"][data-type="radio|checkbox"][data-disabled] {
  /* styles for disabled state */
}
```

### Using arrows

When using arrows within the menu, you can style it using css variables.

```css
[data-part="arrow"] {
  --arrow-size: 20px;
  --arrow-background: red;
}
```

### Checked option item state

When an option item is checked, it is given a `data-state` attribute.

```css
[data-part="item"][data-type="radio|checkbox"][data-state="checked"] {
  /* styles for checked state */
}
```

## Methods and Properties

### Machine Context

The menu machine exposes the following context properties:

<ContextTable name="menu" />

### Machine API

The menu `api` exposes the following methods:

<ApiTable name="menu" />

### Data Attributes

<DataAttrTable name="menu" />

### CSS Variables

<CssVarTable name="menu" />

## Accessibility

Uses
[aria-activedescendant](https://www.w3.org/WAI/ARIA/apg/patterns/menu-button/examples/menu-button-actions-active-descendant/)
pattern to manage focus movement among menu items.

### Keyboard Interactions

<KeyboardTable name="menu" />
